﻿// Copyright (c) Microsoft Corporation.
// This sample code is provided "as is" without warranty of any kind. 

using System;
using System.Data;
using System.Diagnostics;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Channels;
using QueryService = CallContextApplication.QueryServiceReference;

namespace CallContextApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            var callContext = new CallContext(); // PartitionKey = "initial"
            Program.ExecuteDataAreaQuery(callContext);

            Console.WriteLine();

            // 1. Create a new Parition - http://technet.microsoft.com/EN-US/library/jj677455.aspx
            // 2. Open the AX client to show created partition - http://technet.microsoft.com/EN-US/library/jj670112.aspx
            // 3. Create company accounts - http://technet.microsoft.com/en-us/library/dd362102.aspx
            callContext.PartitionKey = "Partition"; // 4. Set value as appropriate

            try
            {
                Program.ExecuteDataAreaQuery(callContext);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }            

            Debugger.Break();
        }

        /// <summary>
        /// Executes the query using the passed in Call Context and prints out the result.
        /// </summary>
        /// <param name="callContext">A <c>CallContext</c> object with context information about the service call.</param>
        public static void ExecuteDataAreaQuery(CallContext callContext)
        {
            // Initilize the service client and get query metadata.
            DataSet dataSet;
            var query = Program.DataAreaQuery;
            var queryClient = CreateQueryClient();

            // Get client channel and the equivalent object cast to service interface
            var channel = queryClient.InnerChannel;
            var queryChannel = (QueryService.IQueryService)channel;

            // Create an operation context scope
            using (OperationContextScope operationContextScope = new OperationContextScope(channel))
            {
                // Add Call Context header to current operation context
                var header = MessageHeader.CreateHeader(CallContext.Name, CallContext.Namespace, callContext);
                OperationContext.Current.OutgoingMessageHeaders.Add(header);

                // Execute service operation
                QueryService.Paging paging = null;
                dataSet = queryChannel.ExecuteQuery(query, ref paging);
            }

            // Print first column of the results.
            foreach (DataRow row in dataSet.Tables[0].Rows)
            {
                Console.WriteLine((string)(row[0]));
            }
        }

        /// <summary>
        /// Call Context data contract to be used as header with system service calls.
        /// </summary>
        [DataContract(Name = CallContext.Name, Namespace = CallContext.Namespace)]
        public class CallContext
        {
            public const string Name = "CallContext";
            public const string Namespace = "http://schemas.microsoft.com/dynamics/2010/01/datacontracts";

            [DataMember]
            public string Company { get; set; }

            [DataMember]
            public string Language { get; set; }

            [DataMember]
            public string LogonAsUser { get; set; }

            [DataMember]
            public string MessageId { get; set; }

            [DataMember]
            public string PartitionKey { get; set; }
        }

        /// <summary>
        /// Constructs and returns an AX query with DataArea table as it's only data source, and field "id" as it's only selected field.
        /// </summary>
        public static QueryService.QueryMetadata DataAreaQuery
        {
            get
            {
                return new QueryService.QueryMetadata()
                {
                    AllowCrossCompany = true,
                    DataSources = new[]
                    { 
                        new QueryService.QueryDataSourceMetadata()
                        {
                            Name = "DataArea",
                            Table = "DataArea",
                            Enabled = true,
                            DynamicFieldList = false, // do not automatically include all fields
                            Fields = new QueryService.QueryFieldMetadata[]
                            {
                                new QueryService.QueryDataFieldMetadata()
                                {
                                    FieldName = "id",
                                    SelectionField = QueryService.SelectionField.Database
                                }
                            }
                        }
                    }
                };
            }
        }

        /// <summary>
        /// Create and configure the service client manually.
        /// </summary>
        /// <remarks>This method ignores app.config settings as they may contain machine specific values.</remarks>
        /// <returns>Configured <c>QueryServiceClient</c> instance.</returns>
        public static QueryService.QueryServiceClient CreateQueryClient()
        {
            var binding = new NetTcpBinding() { TransferMode = TransferMode.Streamed };
            var endpointAddress = new EndpointAddress("net.tcp://localhost:8201/DynamicsAX/Services/QueryService"); // Modify as appropriate
            return new QueryService.QueryServiceClient(binding, endpointAddress);
        }
    }
}
